const tile = new ol.layer.Tile({
    source: new ol.source.XYZ({
        url: 'http://webrd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8'
    })
})
const zoom = 4, center = ol.proj.fromLonLat([107.11040599933166, 34.26271532332011])
var map = new ol.Map({
    target: 'map',
    layers: [
        tile
    ],
    view: new ol.View({
        center,
        zoom
    })
});

class MeasureTool {
    constructor(map) {
        this.map = map
        this.vectorSource = new ol.source.Vector({
            features: []
        })
        this.measureType = ''
        this.coords = []
        this.overlays = []
        this.toolTipDom = document.createElement('div')
        this.toolTipDom.classList.add('measure-result')
        this.toolTip = new ol.Overlay({
            element: this.toolTipDom,
            positioning: 'center-left',
            offset: [5, 0]
        })
        this.map.addOverlay(this.toolTip)
        this.vectorLayer = new ol.layer.Vector({
            source: this.vectorSource,
            style: this._styleFunction
        })
        this.map.addLayer(this.vectorLayer)
    }

    _setDblClickZoom(active = true) {
        const dblClickInteraction = map
            .getInteractions()
            .getArray()
            .find(interaction => {
                return interaction instanceof ol.interaction.DoubleClickZoom
            })
        dblClickInteraction.setActive(active)
    }

    _addResult(text, coord) {
        const dom = document.createElement('div')
        dom.classList.add('measure-result')
        dom.innerText = text
        const overlay = new ol.Overlay({
            element: dom,
            positioning: 'center-left',
            offset: [3, 0]
        })
        this.map.addOverlay(overlay)
        this.overlays.push(overlay)
        overlay.setPosition(coord)
    }

    _addClear(coord) {
        const that = this
        const dom = document.createElement('div')
        dom.classList.add('measure-result')
        dom.classList.add('close')
        dom.innerText = '×'
        const overlay = new ol.Overlay({
            element: dom,
            positioning: 'top-left',
            offset: [3, -30]
        })
        this.map.addOverlay(overlay)
        this.overlays.push(overlay)
        overlay.setPosition(coord)
        dom.onclick = () => {
            // 清除测量
            that._removeOverlays()
            that.vectorSource.clear()
            that.coords = []
            that.toolTip.setPosition(null)
        }
    }

    _getFormatLength(length) {
        return length > 1000 ? (length / 1000).toFixed(2) + 'km' : length.toFixed(0) + 'm'
    }

    _registerMapEvt() {
        const that = this
        const clickFunction = (e) => {
            if(that.measureType === '') return
            const coord = e.coordinate
            that.coords.push(coord)
            if(that.measureType === 'length') {
                let text = ''
                if(that.coords.length === 1) {
                    text = '起点'
                } else {
                    const len = that.coords.length
                    const geom = new ol.geom.LineString([that.coords[len - 2], that.coords[len - 1]])
                    text = that._getFormatLength(geom.getLength())
                }
                that._addResult(text, coord)
            }
        }
        const dblclickFunction = (e) => {
            if(that.measureType === '') return
            // dblclick会添加两次，删除一个
            that.coords.length = that.coords.length - 1
            let geom = null
            if(that.measureType === 'length') {
                geom = new ol.geom.LineString(that.coords)
            } else {
                that.coords.push(that.coords[0])
                geom = new ol.geom.Polygon([that.coords])
            }
            const feature = new ol.Feature({
                geometry: geom
            })
            that.vectorSource.clear()
            that.vectorSource.addFeature(feature)

            that.measureType = ''
            setTimeout(() => {
                // 删除最后一个
                const len = that.overlays.length
                if(len > 2) {
                    that.map.removeOverlay(that.overlays[len - 1])
                    that.map.removeOverlay(that.overlays[len - 2])
                    that.overlays.pop()
                    that.overlays.pop()
                }

                const coord = e.coordinate
                that._addClear(coord)

                that.coords = []

                that._setDblClickZoom(true)
                that.map.un('click', clickFunction)
                that.map.un('pointermove', mousemoveFunction)
                that.map.un('dblclick', dblclickFunction)
            }, 100)
        }
        const mousemoveFunction = (e) => {
            if(that.measureType === '') return
            const coord = e.coordinate
            let coords = [...that.coords]
            coords.push(coord)
            that.toolTip.setPosition(coord)
            let tips = ''
            that.vectorSource.clear()
            if(that.coords.length === 0) {
                tips = '点击地图开始测量'
            } else {
                if(that.measureType === 'length') {
                    // 获取测量结果
                    const geom = new ol.geom.LineString(coords)
                    tips = that._getFormatLength(geom.getLength())
                    const feature = new ol.Feature({
                        geometry: geom
                    })
                    that.vectorSource.addFeature(feature)
                } else {
                    if(that.coords.length < 2) {
                        tips = '点击地图继续测量'
                        const geom = new ol.geom.LineString(coords)
                        const feature = new ol.Feature({
                            geometry: geom
                        })
                        that.vectorSource.addFeature(feature)
                    } else {
                        // 获取测量结果
                        coords.push(coords[0])
                        const geom = new ol.geom.Polygon([coords])
                        tips = geom.getArea()
                        tips = tips > 1000 ? (tips / 1000000).toFixed(2) + 'km²' : tips.toFixed(0) + 'm²'
                        const feature = new ol.Feature({
                            geometry: geom
                        })
                        that.vectorSource.addFeature(feature)
                    }
                }
            }
            that.toolTipDom.innerText = tips
        }
        that.map.on('click', clickFunction)
        that.map.on('pointermove', mousemoveFunction)
        that.map.on('dblclick', dblclickFunction)
    }

    _styleFunction(feat) {
        const styles = [new ol.style.Style({
            stroke: new ol.style.Stroke({
                color: '#ff0000',
                width: 2
            }),
            fill: new ol.style.Fill({
                color: 'rgba(255,0,0,0.2)'
            })
        })]
        const geomType = feat.getGeometry().getType()
        let coords = feat.getGeometry().getCoordinates()
        if(geomType === 'Polygon') coords = coords[0]
        coords.forEach(coord => {
            styles.push(new ol.style.Style({
                geometry: new ol.geom.Point(coord),
                image: new ol.style.Circle({
                    radius: 3,
                    stroke: new ol.style.Stroke({
                        color: '#f00',
                        width: 2
                    }),
                    fill: new ol.style.Fill({
                        color: '#ffffff'
                    })
                })
            }))
        })

        return styles
    }

    activeMeasure(type = 'length') {
        this.measureType = type
        this.coords = []
        this._registerMapEvt()
        this._setDblClickZoom(false)
        this._removeOverlays()
    }

    _removeOverlays() {
        this.overlays.forEach(overlay => {
            this.map.removeOverlay(overlay)
        })
    }
}


const tool = new MeasureTool(map)
document.getElementById('length').onclick = () => {
    tool.activeMeasure('length')
}
document.getElementById('area').onclick = () => {
    tool.activeMeasure('area')
}
